﻿
#include "stdafx.h"
#include "colordef.h"
#include "alpha_x86.inl"
#include "alpha_sse.inl"
#include "alpha_sse2.inl"

//////////////////////////////////////////////////////////////////////////

VOID CCALL AlphaBlend32LevelSSE2(WORD src, LPVOID dest, UINT pitch, UINT cx, UINT cy, BYTE alpha)
{
	// SSE2要求必须把数据对齐到16字节边界上才可以使用MOVDQA高速指令
	ALIGN(16) static const QWORD COLORMASK[2] = { 0x07e0f81f07e0f81f, 0x07e0f81f07e0f81f };
	ALIGN(16) static const QWORD THREETHREE[2] = { 0x0003000300030003, 0x0003000300030003 };

	LPBYTE line = static_cast<LPBYTE>(dest);
	BYTE alpha_p[] = { alpha, alpha, alpha, alpha };
	WORD src_p[] = { src, src, src, src };

	__asm
	{
		movq		mm4, THREETHREE
		movq		mm5, COLORMASK
		movdqa		xmm4, THREETHREE
		movdqa		xmm5, COLORMASK
	}

	UINT loop = cx >> 2;

	switch (cx & 0x3)
	{
	case 3:
		for (; cy; cy--, line += pitch)
		{
			LPWORD img = reinterpret_cast<LPWORD>(line);

			for (UINT i = loop; i; i--, img += 4)
				AlphaBlend32LevelSSE2(src_p, img, alpha_p);

			AlphaBlend32LevelSSE(src_p, img, alpha_p);
			AlphaBlend32LevelX86(src_p, img + 2, alpha_p);
		}
		break;
	case 2:
		for (; cy; cy--, line += pitch)
		{
			LPWORD img = reinterpret_cast<LPWORD>(line);

			for (UINT i = loop; i; i--, img += 4)
				AlphaBlend32LevelSSE2(src_p, img, alpha_p);

			AlphaBlend32LevelSSE(src_p, img, alpha_p);
		}
		break;
	case 1:
		for (; cy; cy--, line += pitch)
		{
			LPWORD img = reinterpret_cast<LPWORD>(line);

			for (UINT i = loop; i; i--, img += 4)
				AlphaBlend32LevelSSE2(src_p, img, alpha_p);

			AlphaBlend32LevelX86(src_p, img, alpha_p);
		}
		break;
	default:
		for (; cy; cy--, line += pitch)
		{
			LPWORD img = reinterpret_cast<LPWORD>(line);

			for (UINT i = loop; i; i--, img += 4)
				AlphaBlend32LevelSSE2(src_p, img, alpha_p);
		}
		break;
	}

	__asm emms
}

VOID CCALL AlphaBlend32LevelSSE2(LPCVOID src, UINT src_pitch, LPVOID dest, UINT dest_pitch, LPCVOID alpha, UINT alpha_pitch, UINT cx, UINT cy)
{
	// SSE2要求必须把数据对齐到16字节边界上才可以使用MOVDQA高速指令
	ALIGN(16) static const QWORD COLORMASK[2] = { 0x07e0f81f07e0f81f, 0x07e0f81f07e0f81f };
	ALIGN(16) static const QWORD THREETHREE[2] = { 0x0003000300030003, 0x0003000300030003 };

	LPCBYTE src_ln = static_cast<LPCBYTE>(src);
	LPBYTE dest_ln = static_cast<LPBYTE>(dest);
	LPCBYTE alpha_ln = static_cast<LPCBYTE>(alpha);

	__asm
	{
		movq		mm4, THREETHREE
		movq		mm5, COLORMASK
		movdqa		xmm4, THREETHREE
		movdqa		xmm5, COLORMASK
	}

	UINT loop = cx >> 2;

	switch (cx & 0x3)
	{
	case 3:
		for (; cy; cy--, src_ln += src_pitch, dest_ln += dest_pitch, alpha_ln += alpha_pitch)
		{
			LPCWORD src_ptr = reinterpret_cast<LPCWORD>(src_ln);
			LPWORD dest_ptr = reinterpret_cast<LPWORD>(dest_ln);
			LPCBYTE alpha_ptr = alpha_ln;

			// TODO: 如果事先可以判断行数据对齐了16字节边界则可以用MOVDQA做进一步优化

			for (UINT i = loop; i; i--, src_ptr += 4, dest_ptr += 4, alpha_ptr += 4)
				AlphaBlend32LevelSSE2(src_ptr, dest_ptr, alpha_ptr);

			AlphaBlend32LevelSSE(src_ptr , dest_ptr, alpha_ptr);
			AlphaBlend32LevelX86(src_ptr + 2, dest_ptr + 2, alpha_ptr + 2);
		}
		break;
	case 2:
		for (; cy; cy--, src_ln += src_pitch, dest_ln += dest_pitch, alpha_ln += alpha_pitch)
		{
			LPCWORD src_ptr = reinterpret_cast<LPCWORD>(src_ln);
			LPWORD dest_ptr = reinterpret_cast<LPWORD>(dest_ln);
			LPCBYTE alpha_ptr = alpha_ln;

			// TODO: 如果事先可以判断行数据对齐了16字节边界则可以用MOVDQA做进一步优化

			for (UINT i = loop; i; i--, src_ptr += 4, dest_ptr += 4, alpha_ptr += 4)
				AlphaBlend32LevelSSE2(src_ptr, dest_ptr, alpha_ptr);

			AlphaBlend32LevelSSE(src_ptr , dest_ptr, alpha_ptr);
		}
		break;
	case 1:
		for (; cy; cy--, src_ln += src_pitch, dest_ln += dest_pitch, alpha_ln += alpha_pitch)
		{
			LPCWORD src_ptr = reinterpret_cast<LPCWORD>(src_ln);
			LPWORD dest_ptr = reinterpret_cast<LPWORD>(dest_ln);
			LPCBYTE alpha_ptr = alpha_ln;

			// TODO: 如果事先可以判断行数据对齐了16字节边界则可以用MOVDQA做进一步优化

			for (UINT i = loop; i; i--, src_ptr += 4, dest_ptr += 4, alpha_ptr += 4)
				AlphaBlend32LevelSSE2(src_ptr, dest_ptr, alpha_ptr);

			AlphaBlend32LevelX86(src_ptr, dest_ptr, alpha_ptr);
		}
		break;
	case 0:
		for (; cy; cy--, src_ln += src_pitch, dest_ln += dest_pitch, alpha_ln += alpha_pitch)
		{
			LPCWORD src_ptr = reinterpret_cast<LPCWORD>(src_ln);
			LPWORD dest_ptr = reinterpret_cast<LPWORD>(dest_ln);
			LPCBYTE alpha_ptr = alpha_ln;

			// TODO: 如果事先可以判断行数据对齐了16字节边界则可以用MOVDQA做进一步优化

			for (UINT i = loop; i; i--, src_ptr += 4, dest_ptr += 4, alpha_ptr += 4)
				AlphaBlend32LevelSSE2(src_ptr, dest_ptr, alpha_ptr);
		}
		break;
	}

	__asm emms
}

//////////////////////////////////////////////////////////////////////////
